#!/usr/local/bin/python
#

from optparse import OptionParser
import StringIO
import sys
from unittest import TestCase

import term.framework
from term.framework import AbnormalTermination, Terminate, UsageError

class Dummy(object):
    pass

class TestApplication(TestCase):

    class TestApp(term.framework.Application):

        def run(self, options, args):
            self.res = 'one'

        def configure_parser(self, parser):
            parser.add_option('--option', dest='hereOpt')

    def test_application(self):
        """Test creation and running of an application"""
        app = term.framework.Application()
        self.assertEquals(0, app.main([]))

    def test_run(self):
        """Check that the run method does so"""
        app = term.framework.Application()
        options, args = Dummy(), Dummy()
        app.run(options, args)

    def test_locally_defined_app(self):
        """Locally defined app works"""
        app = self.TestApp()
        self.assertEquals(0, app.main([]))

    def start_capturing_stderr(self):
        (self.stderr, self.sys_stderr) = (StringIO.StringIO(), sys.stderr)
        sys.stderr = self.stderr

    def stop_capturing_stderr(self):
        sys.stderr = self.sys_stderr

    def start_capturing_stdout(self):
        (self.stdout, self.sys_stdout) = (StringIO.StringIO(), sys.stdout)
        sys.stdout = self.stdout

    def stop_capturing_stdout(self):
        sys.stdout = self.sys_stdout

    def test_abnormal_termination_with_output(self):
        """Verify that abnormal termination with output works"""
        app = self.TestApp()
        def raise_abnormal_termination_with_message(x, y):
            raise AbnormalTermination("message reported")
        app.run = raise_abnormal_termination_with_message
        self.start_capturing_stderr()
        try:
            self.assertEquals(1, app.main([]))
        finally:
            self.stop_capturing_stderr()
        self.assertEquals("message reported\n", self.stderr.getvalue())

    def test_abnormal_termination_without_output(self):
        """Verify that abnormal termination without output works"""
        app = self.TestApp()
        def raise_abnormal_termination_without_message(x, y):
            raise AbnormalTermination()
        app.run = raise_abnormal_termination_without_message
        self.start_capturing_stderr()
        try:
            self.assertEquals(1, app.main([]))
        finally:
            self.stop_capturing_stderr()
        self.failUnless(self.stderr.getvalue() == "")

    def test_normal_termination_with_output(self):
        """Verify that normal termination with output works"""
        app = self.TestApp()
        def raise_termination_without_message(x, y):
            raise Terminate("Good job")
        app.run = raise_termination_without_message
        self.start_capturing_stderr()
        self.start_capturing_stdout()
        try:
            self.assertEquals(0, app.main([]))
        finally:
            self.stop_capturing_stderr()
            self.stop_capturing_stdout()
        self.failUnless(self.stderr.getvalue() == "")
        self.failUnless(self.stdout.getvalue() == "Good job\n")

    def test_normal_termination_without_output(self):
        """Verify that normal termination without output works"""
        app = self.TestApp()
        def raise_termination_without_message(x, y):
            raise Terminate()
        app.run = raise_termination_without_message
        self.start_capturing_stderr()
        self.start_capturing_stdout()
        try:
            self.assertEquals(0, app.main([]))
        finally:
            self.stop_capturing_stderr()
            self.stop_capturing_stdout()
        self.failUnless(self.stderr.getvalue() == "")
        self.failUnless(self.stdout.getvalue() == "")

    def test_parse_command_line_raises_usage_error(self):
        """Parse command should raise a UsageError when options are wrong"""
        app = self.TestApp()
        app.argv = ["--foo"]
        app.parser = OptionParser(usage="foo")
        self.failUnlessRaises(UsageError, app.parse_command_line)

    def test_nonspecific_exception(self):
        """Verify that unhandled terminations generate failures"""
        app = self.TestApp()
        def raise_nonspecific_exception(x, y):
            raise Exception("Horrible termination")
        app.run = raise_nonspecific_exception
        self.start_capturing_stderr()
        self.assertEquals(1, app.main([]))
        self.stop_capturing_stderr()
        self.failUnless(self.stderr.getvalue())

    def test_system_exit(self):
        """Verify that system exit is trapped, and the exit code propagates"""
        app = self.TestApp()
        distinctive_exit_value = 435
        def do_system_exit(x, y):
            sys.exit(distinctive_exit_value)
        app.run = do_system_exit
        try:
            app.main([])
            self.fail()
        except SystemExit, e:
            self.assertEquals(distinctive_exit_value, e.code)

    def test_populate_parser(self):
        """Test population of parser"""
        app = self.TestApp()
        argv = ["This", "--option", "here", "with", "stuff"]
        parser = OptionParser()
        app.configure_parser(parser)
        parser.parse_args(argv)

    def test_arg_parsing(self):
        """Parse arguments"""
        app = self.TestApp()
        app.argv = ["This", "--option", "here", "with", "stuff"]
        app.parser = OptionParser()
        app.parser.add_option("--option", dest="hereOpt")
        app.parse_command_line()
        self.failUnless(app.options.hereOpt == 'here')
        self.failUnless(app.args == ["This", 'with', 'stuff'])
